const path = require('path');
const fs = require('fs');
const postcss = require('postcss');
const babel = require('babel-core');
const traverse = require('babel-traverse').default;

const util = require('./util');
const pathExt = require('./path-ext');

exports.getRefernces = async (source, opts) => {
  let refResult = [];
  let files = await util.getAllFiles(source);
  files.forEach(file => {
    let extname = path.extname(file);
    switch (extname) {
      case '.js':
        refResult.push(jsReferences(file, opts.jsConfig));
        break;
      case '.scss':
      case '.less':
        refResult.push(styleReferences(file, opts.jsConfig));
        break;
      case '.vue':
        refResult.push(vueReferences(file, opts));
        break;
    }
  });
  return refResult;
};

function _jsReferences (source, code = '', jsConfig = {}) {
  let refs = [];
  let parser = babel.transform(code);
  traverse(parser.ast, {
    enter (_path) {
      let result;
      if (_path.node.type === 'ImportDeclaration') {
        let astValue = _path.node.source.value;
        result = pathExt.parsePath(source, astValue, jsConfig);
      }
      if (_path.node.type === 'CallExpression' && _path.node.callee.name === 'require') {
        let astValue = _path.node.arguments[0].value;
        result = pathExt.parsePath(source, astValue, jsConfig);
      }
      if (result) {
        refs.push(result);
      }
    }
  });
  return refs;
}

function jsReferences (source, jsConfig = {}) {
  let code = fs.readFileSync(source, 'utf-8');
  let refs = _jsReferences(source, code, jsConfig);
  return {
    source,
    refs
  };
}

function styleReferences (source, styleConfig = {}) {
  let code = fs.readFileSync(source, 'utf-8');
  let refs = _styleReferences(source, code, styleConfig);
  return {
    source,
    refs
  };
}

function _styleReferences (source, code, styleConfig = {}) {
  let refs = [];
  let root = postcss.parse(code);
  root.walkAtRules(rule => {
    let result;
    if (rule.name === 'import') {
      result = pathExt.parsePath(source, rule.params, styleConfig);
    }
    if (result) {
      refs.push(result);
    }
  });
}

function vueReferences (source, config = {}) {
  let refs = [];
  let code = fs.readFileSync(source, 'utf-8');

  let scriptCode = code.match(/<script>([\s\S]*)<\/script>/) ? RegExp.$1 : '';
  refs = [..._jsReferences(source, scriptCode, config.jsConfig)];

  let styleCode = code.match(/<style>([\s\S]*)<\/style>/) ? RegExp.$1 : '';
  refs = [..._styleReferences(source, styleCode, config.styleConfig)];

  return {
    source: source,
    refs
  };
}
